package com.zzyl.security;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.zzyl.constant.UserCacheConstant;
import com.zzyl.properties.JwtTokenManagerProperties;
import com.zzyl.utils.JwtUtil;
import com.zzyl.utils.ObjectUtil;
import com.zzyl.vo.UserAuth;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.function.Supplier;

/**
 * 自定义的授权管理器
 */
@Component
public class JwtAuthorizationManager implements AuthorizationManager<RequestAuthorizationContext> {

    @Autowired
    private JwtTokenManagerProperties jwtTokenManagerProperties;

    @Autowired
    private StringRedisTemplate redisTemplate;

    //定义匹配路径对象
    private AntPathMatcher antPathMatcher=new AntPathMatcher();
    /**
     * 授权方法
     */
    @Override
    public AuthorizationDecision check(Supplier<Authentication> authentication, RequestAuthorizationContext requestAuthorizationContext) {

        //1.获取请求头中的token
        HttpServletRequest request = requestAuthorizationContext.getRequest();
        String token = request.getHeader("Authorization");

        //2.判断token是否为空
        if (StrUtil.isEmpty(token)) {
            return new AuthorizationDecision(false);
        }

        //3.解析token
        Claims claims = JwtUtil.parseJWT(jwtTokenManagerProperties.getBase64EncodedSecretKey(), token);
        if (ObjectUtil.isEmpty(claims)) {
            return new AuthorizationDecision(false);
        }
        //3.5 获取用户信息
        String userAuthStr = (String) claims.get("user");
        UserAuth userAuth = JSONObject.parseObject(userAuthStr, UserAuth.class);

        //4.从redis中获取url列表
        String accessUrlsCacheKey = UserCacheConstant.ACCESS_URLS_CACHE+userAuth.getId();
        String accessUrlStr = redisTemplate.opsForValue().get(accessUrlsCacheKey);
        List<String> accessUrlList=null;
        //5.验证当前用户的资源权限是否匹配redis中url列表
        //5.1 把json字符串转成list集合
        if (StrUtil.isNotEmpty(accessUrlStr)) {
            //["PUT/dept","DELETE/dept/**"]
            accessUrlList= JSONUtil.toList(accessUrlStr, String.class);
        }

        //5.2 获取当前用户的请求资源
            //先获取请求路径  /dept/**
        String requestURI = request.getRequestURI();
            //在获取请求方式  PUT
        String method = request.getMethod();
        //    PUT/dept/**
        String targeUrl=method+requestURI;
            //匹配资源
        if(!CollectionUtils.isEmpty(accessUrlList)){
            for (String accessUrl : accessUrlList) {
                //表示匹配成功
                if (antPathMatcher.match(accessUrl,targeUrl)) {
                    return new AuthorizationDecision(true);
                }
            }
        }
        //如果匹配，则放行，否则403
        return new AuthorizationDecision(true);
    }
}
